/**
 * The Community Project
 * Copyright Team1 Productions
 * 
 * Joshua Amick
 * Stephen Cunningham
 * Thema Davis
 * Tomika Dawson
 * Lucie DeCristofaro
 * 
 * All Rights Reserved.
 */

package com.business;

import java.sql.Timestamp;
import java.util.List;
import java.util.Random;

import com.constants.CharacterMap;
import com.constants.UserPermissions;
import com.dao.AnnouncementDAO;
import com.dao.EmailDAO;
import com.dao.EventDAO;
import com.dao.ProfileDAO;
import com.dao.UserDAO;
import com.domain.Announcement;
import com.domain.Email;
import com.domain.Event;
import com.domain.Profile;
import com.domain.User;
import com.util.CommunityEmailer;
import com.util.PasswordEncoder;

public class PrivateManager{
	//Handles to all the DAO's
	protected AnnouncementDAO announcementDAO;
	protected EmailDAO emailDAO;
	protected EventDAO eventDAO;
	protected ProfileDAO profileDAO;
	protected UserDAO userDAO;
	protected PasswordEncoder passEncode;
	protected CommunityEmailer communityEmailer;
	
	public AnnouncementDAO getAnnouncementDAO() {
		return announcementDAO;
	}
	public void setAnnouncementDAO(AnnouncementDAO announcementDAO) {
		this.announcementDAO = announcementDAO;
	}
	public EmailDAO getEmailDAO() {
		return emailDAO;
	}
	public void setEmailDAO(EmailDAO emailDAO) {
		this.emailDAO = emailDAO;
	}
	public EventDAO getEventDAO() {
		return eventDAO;
	}
	public void setEventDAO(EventDAO eventDAO) {
		this.eventDAO = eventDAO;
	}
	public ProfileDAO getProfileDAO() {
		return profileDAO;
	}
	public void setProfileDAO(ProfileDAO profileDAO) {
		this.profileDAO = profileDAO;
	}
	public UserDAO getUserDAO() {
		return userDAO;
	}
	public void setUserDAO(UserDAO userDAO) {
		this.userDAO = userDAO;
	}
	public void setPassEncode(PasswordEncoder passEncode) {
		this.passEncode = passEncode;
	}
	public void setCommunityEmailer(CommunityEmailer communityEmailer) {
		this.communityEmailer = communityEmailer;
	}
	
	//Saving Profile for a user
	//This method is called by an action with the appropriate parameters to save a profile for the given user
	public User saveProfileForUser(User user, String firstName, String lastName, String address1, String address2,
			String city, String state, String zip, String secondaryEmail, String phone, String employer, 
			String positionDescription, Timestamp employmentStartDate, String education, String major, 
			Timestamp graduationDate, String professionalOrganizations, String studentOrganizations, 
			boolean publicViewable){
		if(user!=null){
			Profile profile = null;
			if(user.getProfile()!=null&&user.getProfile().getKeyId()>0){
				profile = this.profileDAO.getProfileByKeyId(user.getProfile().getKeyId());
				profile.setFirstName(firstName);
				profile.setLastName(lastName);
				profile.setAddress1(address1);
				profile.setAddress2(address2);
				profile.setState(state);
				profile.setZip(zip);
				profile.setSecondaryEmail(secondaryEmail);
				profile.setPhone(phone);
				profile.setEmployer(employer);
				profile.setPositionDescription(positionDescription);
				profile.setEmploymentStartDate(employmentStartDate);
				profile.setEducation(education);
				profile.setMajor(major);
				profile.setGraduationDate(graduationDate);
				profile.setProfessionalOrganizations(professionalOrganizations);
				profile.setStudentOrganizations(studentOrganizations);
				profile.setPublicViewable(publicViewable);
			}
			else{
				profile = this.profileDAO.buildProfile(firstName, lastName, address1, address2, city, state, zip, 
						secondaryEmail, phone, employer, positionDescription, employmentStartDate, education, major, 
						graduationDate, professionalOrganizations, studentOrganizations, publicViewable);
			}
			this.profileDAO.save(profile);
			user.setProfile(profile);
			return this.userDAO.save(user);
		}
		else return null;
	}
	
	//SaveUser
	//This method is for saving new users and completing their profile if information is provided.
	public User saveUser(String username, User createdBy, String email, User lastUpdateUser, 
			String password, UserPermissions userPermissions, boolean deleted, 
			boolean approved,String firstName, String lastName, String address1, String address2,
			String city, String state, String zip, String secondaryEmail, String phone, String employer, 
			String positionDescription, Timestamp employmentStartDate, String education, String major, 
			Timestamp graduationDate, String professionalOrganizations, String studentOrganizations, 
			boolean publicViewable, boolean subscribed){
		User user = null;
		user = this.userDAO.getUserByUsername(username);
		Profile profile = null;
		if((user!=null)&&(user.getKeyId()!=null)&&(user.getKeyId()>0)){
			profile = user.getProfile();
			if(profile!=null&&profile.getKeyId()>0){
				profile = this.userDAO.buildProfile(profile, firstName, lastName, address1, address2, city, state, zip, 
					secondaryEmail, phone, employer, positionDescription, employmentStartDate, 
					education, major, graduationDate, professionalOrganizations, studentOrganizations, 
					publicViewable);
				
			}
			else{
				profile = new Profile();
				profile = this.userDAO.buildProfile(profile, firstName, lastName, address1, address2, city, state, zip, 
						secondaryEmail, phone, employer, positionDescription, employmentStartDate, 
						education, major, graduationDate, professionalOrganizations, studentOrganizations, 
						publicViewable);
			}
			profile = this.profileDAO.save(profile);
			user.setSubscribedToEmails(subscribed);
			user = this.userDAO.saveUser(user.getKeyId(), username, createdBy, email, lastUpdateUser, 
					password, userPermissions, profile, deleted, approved);
		}
		else{
			profile = new Profile();
			profile = this.userDAO.buildProfile(profile, firstName, lastName, address1, address2, city, state, zip, 
					secondaryEmail, phone, employer, positionDescription, employmentStartDate, 
					education, major, graduationDate, professionalOrganizations, studentOrganizations, 
					publicViewable);
			profile = this.profileDAO.save(profile);
			user = new User();
			user.setSubscribedToEmails(subscribed);
			user = this.userDAO.saveUser(null, username, createdBy, email, lastUpdateUser, 
					password, userPermissions, profile, deleted, approved);
		}
		return user;
	}
	
	//Saving and existing event
	public Event saveEvent(Long keyId, User user, Timestamp startDate, Timestamp endDate, boolean reoccuringEvent, String eventTitle,
			String eventDescription, String eventLocation, String details, boolean publicViewable, boolean approved){
		return this.eventDAO.saveEvent(keyId, user, startDate, endDate, reoccuringEvent, eventTitle, eventDescription, eventLocation, details, publicViewable, approved);
	}
	
	//Savind an existing announcement
	public Announcement saveAnnouncement(Long keyId, User user, Timestamp startDate, Timestamp endDate, String announcementTitle,
			String announcementDescription, String announcementDetails, boolean publicViewable, boolean approved){
		return this.announcementDAO.saveAnnouncement(keyId, user, startDate, endDate, announcementTitle, announcementDescription, announcementDetails, publicViewable, approved);
	}
	
	//testMethod
	public void test() {
//		Timestamp now = new Timestamp(System.currentTimeMillis());
//		saveUser("testUser0", null, "amickj@gmail.com", null, "community", UserPermissions.PUBLIC, 
//				false, true, "Test0", "User0", "123 Some St.", "", "Columbia", "South Carolina", "29201", "", 
//				"803-777-7777", "USC", "Student", now, "BS", "Computer Science", now, 
//				"", "", true);
//		User root = this.getUserDAO().saveUser(null, "root", null, "amickj@gmail.com", null, 
//				"root", UserPermissions.ADMIN, null, false, true);
		//User root = this.getUserDAO().getUserByKeyId(Long.parseLong("2"));
		/*saveUser("testUser0", root, "amickj@gmail.com", root, "community", UserPermissions.PUBLIC, 
				false, true, "Test0", "User0", "123 Some St.", "", "Columbia", "South Carolina", "29201", "", 
				"803-777-7777", "USC", "Student", now, "BS", "Computer Science", now, 
				"", "", true);*/
	}
	
	//Get top events
	//This method is going to query the database for the events that fit into the two week range for the given date
	public List<Event> getTopEvents() {
		return this.eventDAO.getTopEvents();
	}
	
	//Get top events
	//This method is going to query the database for the announcement that fit into the two week range for the given date
	public List<Announcement> getTopAnnouncements() {
		return this.announcementDAO.getTopAnnouncements();
	}
	
	//Save user password
	public User saveUserPassword(User user, String password1) {
		user.setPassword(password1);
		return this.userDAO.save(user);
	}
	
	//Saving emails
	//This method saves emails and depends on the user permissions, it will send the email or make it so that it has to be approved
	public Email saveEmail(User user, String subject, String body, String replyToAddress, boolean toAll,boolean approved) {
		Email email = new Email();
		Timestamp now = new Timestamp(System.currentTimeMillis());
		if(user.getUserPermissions()==UserPermissions.ADMIN){
			email.setApproved(true);
		}else email.setApproved(approved);
		email.setCreatedBy(user);
		email.setCreationDate(now);
		email.setDeleted(false);
		email.setEmailMessage(body);
		email.setEmailSubject(subject);
		email.setLastModDate(now);
		email.setLastUpdateUser(user);
		email.setPublicEmail(toAll);
		email.setReplyToAddress(replyToAddress);
		email = this.emailDAO.save(email);
		if(email.isApproved())communityEmailer.addEmail(email.getKeyId());
		return email;
	}
	
	//Save Email By Admin
	//This method saves the email and sends it if the users credentials are correct
	public Email saveEmailByAdmin(User user, Email email){
		Timestamp now = new Timestamp(System.currentTimeMillis());
		if(user.getUserPermissions()==UserPermissions.ADMIN){
			email.setApproved(true);
		}else email.setApproved(false);
		email.setLastModDate(now);
		email.setLastUpdateUser(user);
		return this.emailDAO.save(email);
	}
	
	//This method returns all events in the system
	public List<Event> getAllEvents(){
		return this.eventDAO.getAllEvents();
	}
	
	//This method returns all announcements in the system
	public List<Announcement> getAllAnnouncements(){
		return this.announcementDAO.getAllAnnouncements();
	}
	
	//This mehtod returns all users in the system
	public List<User> getAllUsers() {
		return this.userDAO.getAllUsers();
	}
	
	//This method returns the user to match the given keyid
	public User getUserByKeyId(Long keyId) {
		return this.userDAO.getUserByKeyId(keyId);
	}
	
	//This method returns all users waiting to be approved
	public List<User> getPendingUsers() {
		return this.userDAO.getPendingUsers();
	}
	
//	This method returns all events waiting to be approved
	public List<Event> getPendingEvents() {
		return this.eventDAO.getPendingEvents();
	}
	
//	This method returns all announcements waiting to be approved
	public List<Announcement> getPendingAnnouncements() {
		return this.announcementDAO.getPendingAnnouncements();
	}
	
//	This method returns all emails waiting to be approved
	public List<Email> getPendingEmails() {
		return this.emailDAO.getPendingEmails();
	}
	
	//This method is for approving users to use the system
	public User approveUser(User admin, Long approvedUserKeyId){
		User approvedUser = this.userDAO.getUserByKeyId(approvedUserKeyId);
		Timestamp now = new Timestamp(System.currentTimeMillis());
		if(approvedUser!=null&&approvedUser.getKeyId()>0){
			approvedUser.setApproved(true);
			approvedUser.setLastUpdateUser(admin);
			approvedUser.setLastModDate(now);
			return this.userDAO.save(approvedUser);
		}
		else return null;
	}
	
	//This method is for approving events to be displayed
	public Event approveEvent(User admin, Long approvedEventKeyId){
		Event approvedEvent = this.eventDAO.getEventByKeyId(approvedEventKeyId);
		Timestamp now = new Timestamp(System.currentTimeMillis());
		if(approvedEvent!=null&&approvedEvent.getKeyId()>0){
			approvedEvent.setApproved(true);
			approvedEvent.setLastUpdateUser(admin);
			approvedEvent.setLastModDate(now);
			return this.eventDAO.save(approvedEvent);
		}
		else return null;
	}
	
	//This method is for approving announcements to be displayed
	public Announcement approveAnnouncement(User admin, Long approvedAnnouncementKeyId){
		Announcement approvedAnnouncement = this.announcementDAO.getAnnouncementByKeyId(approvedAnnouncementKeyId);
		Timestamp now = new Timestamp(System.currentTimeMillis());
		if(approvedAnnouncement!=null&&approvedAnnouncement.getKeyId()>0){
			approvedAnnouncement.setApproved(true);
			approvedAnnouncement.setLastUpdateUser(admin);
			approvedAnnouncement.setLastModDate(now);
			return this.announcementDAO.save(approvedAnnouncement);
		}
		else return null;
	}
	
	//This method is for approving emails to be sent
	public Email approveEmail(User admin, Long approvedEmailKeyId){
		Email approvedEmail = this.emailDAO.getEmailByKeyId(approvedEmailKeyId);
		Timestamp now = new Timestamp(System.currentTimeMillis());
		if(approvedEmail!=null&&approvedEmail.getKeyId()>0){
			approvedEmail.setApproved(true);
			approvedEmail.setLastUpdateUser(admin);
			approvedEmail.setLastModDate(now);
			return this.emailDAO.save(approvedEmail);
		}
		else return null;
	}
	
	//This method was supposed to be used to initially saved, but is no longer used
	public User saveUserInitial(String username, String password, String email, boolean approved) {
		User newUser = new User();
		Profile blankProfile = new Profile();
		Timestamp now = new Timestamp(System.currentTimeMillis());
		newUser.setSubscribedToEmails(true);
		newUser.setUsername(username);
		newUser.setPassword(password);
		newUser.setCreationDate(now);
		newUser.setLastModDate(now);
		newUser.setEmail(email);
		newUser.setApproved(approved);
		newUser.setUserPermissions(UserPermissions.PUBLIC);
		blankProfile = this.profileDAO.save(blankProfile);
		newUser.setProfile(blankProfile);
		return this.userDAO.save(newUser);
	}
	
	//This method searchs for users by username, first name, last name and major
	public List<User> searchProfiles(String username, String firstName, String lastName, String major) {
		return this.userDAO.searchProfiles(username, firstName, lastName, major);
	}
	
	//This method returns all approved users in the database
	public List<User> getAllApprovedUsers() {
		return this.userDAO.getAllApprovedUsers();
	}
	
//	This method returns the event that matches the given keyid
	public Event getEventByKeyId(Long keyId) {
		return this.eventDAO.getEventByKeyId(keyId);
	}
	
//	This method returns the email that matches the given keyid
	public Email getEmailByKeyId(Long keyId) {
		return this.emailDAO.getEmailByKeyId(keyId);
	}
	
	//This method returns the announcement that matches the given keyid
	public Announcement getAnnouncementByKeyId(Long keyId) {
		return this.announcementDAO.getAnnouncementByKeyId(keyId);
	}
	
	//This method gets all email users who's profiles are set to recieve email.
	public List<User> getAllEmailUsers() {
		return this.userDAO.getAllEmailUsers();
	}
	
	//This method returns al the valid events in the system
	public List<Event> getAllUndeletedEvents() {
		return this.eventDAO.getAllUndeletedEvents();
	}
	
	//This method returns all the valid announcements in the system
	public List<Announcement> getAllUndeletedAnnouncements() {
		return this.announcementDAO.getAllUndeletedAnnouncements();
	}
	
	//This method gets the user by its username
	public User getUserByUsername(String username) {
		return this.getUserDAO().getUserByUsername(username);
	}
	
	//This method generates a random password 
	public String getPasswordForNewUser(){
		CharacterMap map = new CharacterMap();
		Random r1 = new Random();
		int charIndex = 0;
		int numIndex = 0;
		String password = "";
		for(int i = 0; i < 7; i++){
			if(i<5){
				charIndex = r1.nextInt(26)+1;
				char x = map.getCharByNum(charIndex);
				password += x;
			}
			else{
				numIndex = r1.nextInt(10);
				password += numIndex;
			}
		}
		return password;
	}
	
}
